<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Digest Authentication Client</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .container {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
            padding: 40px;
            max-width: 1200px;
            width: 100%;
            position: relative;
            overflow: hidden;
            animation: slideIn 0.6s ease-out;
        }

        @keyframes slideIn {
            from { opacity: 0; transform: translateY(30px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .container::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 4px;
            background: linear-gradient(90deg, #667eea, #764ba2);
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
        }

        .auth-logo {
            font-size: 48px;
            margin-bottom: 20px;
            color: #333;
        }

        h1 {
            color: #333;
            margin-bottom: 10px;
            font-size: 28px;
            font-weight: 700;
        }

        .subtitle {
            color: #666;
            margin-bottom: 30px;
            font-size: 16px;
        }

        .section {
            margin-bottom: 30px;
            padding: 25px;
            background: rgba(255, 255, 255, 0.7);
            border-radius: 15px;
            border: 1px solid rgba(255, 255, 255, 0.3);
            transition: all 0.3s ease;
        }

        .section:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
        }

        .section h2 {
            color: #333;
            margin-bottom: 15px;
            font-size: 20px;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .user-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 20px;
        }

        .user-card {
            background: rgba(255, 255, 255, 0.9);
            padding: 15px;
            border-radius: 10px;
            border: 1px solid rgba(255, 255, 255, 0.3);
            text-align: center;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .user-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }

        .user-card.active {
            border-color: #667eea;
            background: rgba(102, 126, 234, 0.1);
        }

        .user-card h4 {
            color: #333;
            margin-bottom: 5px;
        }

        .user-card p {
            color: #666;
            font-size: 12px;
        }

        .user-email {
            color: #888;
            font-size: 11px;
            font-style: italic;
            margin-top: 5px;
        }

        .form-group {
            margin-bottom: 20px;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #333;
            font-size: 14px;
        }

        input[type="text"], input[type="password"], input[type="email"] {
            width: 100%;
            padding: 12px 16px;
            border: 2px solid #e1e5e9;
            border-radius: 10px;
            font-size: 16px;
            transition: all 0.3s ease;
            background: white;
        }

        input:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }

        .endpoint-section {
            background: rgba(255, 255, 255, 0.8);
            padding: 20px;
            border-radius: 15px;
            border: 1px solid rgba(255, 255, 255, 0.3);
            margin-bottom: 20px;
        }

        .endpoint-section h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 18px;
            font-weight: 600;
        }

        .button-group {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }

        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 10px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            position: relative;
            overflow: hidden;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .btn::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
            transition: left 0.5s;
        }

        .btn:hover::before {
            left: 100%;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
        }

        .btn:active {
            transform: translateY(0);
        }

        .btn-profile { background: linear-gradient(45deg, #4CAF50, #45a049); color: white; }
        .btn-admin { background: linear-gradient(45deg, #FF6B6B, #ee5a52); color: white; }
        .btn-public { background: linear-gradient(45deg, #4ECDC4, #44a08d); color: white; }
        .btn-update { background: linear-gradient(45deg, #9C27B0, #8E24AA); color: white; }
        .btn-clear { background: linear-gradient(45deg, #666, #555); color: white; }
        .btn-reset { background: linear-gradient(45deg, #FF9800, #F57C00); color: white; }

        .console {
            background: #1e1e1e;
            color: #00ff00;
            padding: 20px;
            border-radius: 15px;
            font-family: 'SF Mono', Monaco, monospace;
            font-size: 14px;
            line-height: 1.5;
            min-height: 200px;
            overflow-y: auto;
            border: 1px solid #333;
            position: relative;
        }

        .console::before {
            content: 'Response Console';
            position: absolute;
            top: -10px;
            left: 20px;
            background: #1e1e1e;
            color: #00ff00;
            padding: 0 10px;
            font-size: 12px;
            font-weight: bold;
        }

        .log-success { color: #4CAF50; font-weight: bold; }
        .log-error { color: #FF6B6B; font-weight: bold; }
        .log-info { color: #2196F3; font-weight: bold; }
        .log-warning { color: #FFC107; font-weight: bold; }

        .auth-state {
            background: rgba(255, 255, 255, 0.8);
            padding: 20px;
            border-radius: 15px;
            border: 1px solid rgba(255, 255, 255, 0.3);
            margin-bottom: 20px;
        }

        .auth-state h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 18px;
            font-weight: 600;
        }

        .auth-info {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
        }

        .auth-param {
            background: rgba(255, 255, 255, 0.9);
            padding: 10px;
            border-radius: 8px;
            border: 1px solid rgba(255, 255, 255, 0.3);
        }

        .auth-param-name {
            font-weight: 600;
            color: #333;
            font-size: 12px;
            text-transform: uppercase;
            margin-bottom: 5px;
        }

        .auth-param-value {
            font-family: 'SF Mono', Monaco, monospace;
            font-size: 13px;
            color: #666;
            word-break: break-all;
        }

        .transaction-details {
            display: none;
            margin-top: 20px;
        }

        .transaction-details.visible {
            display: block;
            animation: fadeIn 0.5s ease-out;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .http-message {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 10px;
            margin-bottom: 15px;
            overflow: hidden;
        }

        .http-message-header {
            background: linear-gradient(45deg, #495057, #6c757d);
            color: white;
            padding: 12px 20px;
            font-weight: 600;
            font-size: 14px;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .http-message-content {
            padding: 20px;
            font-family: 'SF Mono', Monaco, monospace;
            font-size: 13px;
            line-height: 1.6;
            background: white;
        }

        .http-message-content pre {
            white-space: pre-wrap;
            word-wrap: break-word;
            word-break: break-all;
            overflow-wrap: break-word;
            margin: 0;
            font-family: inherit;
            font-size: inherit;
        }

        .http-request {
            border-left: 4px solid #007bff;
        }

        .http-request .http-message-header {
            background: linear-gradient(45deg, #007bff, #0056b3);
        }

        .http-response-401 {
            border-left: 4px solid #ffc107;
        }

        .http-response-401 .http-message-header {
            background: linear-gradient(45deg, #ffc107, #e0a800);
        }

        .http-response-success {
            border-left: 4px solid #28a745;
        }

        .http-response-success .http-message-header {
            background: linear-gradient(45deg, #28a745, #1e7e34);
        }

        .http-response-error {
            border-left: 4px solid #dc3545;
        }

        .http-response-error .http-message-header {
            background: linear-gradient(45deg, #dc3545, #c82333);
        }

        .http-method { color: #007bff; font-weight: bold; }
        .http-status-200 { color: #28a745; font-weight: bold; }
        .http-status-401 { color: #ffc107; font-weight: bold; }
        .http-status-error { color: #dc3545; font-weight: bold; }
        .http-header-name { color: #6f42c1; font-weight: bold; }
        .http-header-value { color: #495057; }

        .transaction-flow {
            display: flex;
            align-items: center;
            justify-content: center;
            margin: 20px 0;
            font-size: 24px;
            color: #6c757d;
        }

        @media (max-width: 768px) {
            .container { padding: 20px; margin: 10px; }
            .user-grid { grid-template-columns: 1fr; }
            .button-group { flex-direction: column; }
            .btn { width: 100%; }
            .http-message-content { font-size: 12px; }
            .auth-info { grid-template-columns: 1fr; }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <div class="auth-logo">🔐</div>
        <h1>Digest Authentication Client</h1>
        <p class="subtitle">HTTP Digest Authentication Demo</p>
    </div>

    <div class="section">
        <h2>👥 User Selection</h2>
        <div class="user-grid" id="userGrid">
            <!-- User cards will be generated here -->
        </div>

        <div class="form-group">
            <label for="username">Username:</label>
            <input type="text" id="username" placeholder="Enter username">
        </div>
        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" id="password" placeholder="Enter password">
        </div>
    </div>

    <div class="section">
        <h2>🔑 Authentication State</h2>
        <div class="auth-state">
            <div id="authStateContent">
                <!-- Auth state will be displayed here -->
            </div>
            <div style="margin-top: 15px;">
                <button class="btn btn-reset" id="resetAuthBtn">
                    <span>🔄</span>Reset Auth State
                </button>
            </div>
        </div>
    </div>

    <div class="section">
        <h2>🔒 Protected Endpoints</h2>

        <div class="endpoint-section">
            <h3>📧 Email Management</h3>
            <div class="form-group">
                <label for="newEmail">New Email Address:</label>
                <input type="email" id="newEmail" placeholder="Enter new email address">
            </div>
            <div class="button-group">
                <button class="btn btn-update" id="updateEmailBtn">
                    <span>📧</span>Update Email
                </button>
            </div>
        </div>

        <div class="endpoint-section">
            <h3>🛡️ Protected Routes</h3>
            <div class="button-group">
                <button class="btn btn-profile" data-endpoint="/profile/me">
                    <span>👤</span>Profile
                </button>
                <button class="btn btn-admin" data-endpoint="/admin">
                    <span>👨‍💼</span>Admin
                </button>
            </div>
        </div>

        <div class="endpoint-section">
            <h3>🌐 Public Routes</h3>
            <div class="button-group">
                <button class="btn btn-public" data-endpoint="/public">
                    <span>🌍</span>Public
                </button>
            </div>
        </div>
    </div>

    <div class="section">
        <h2>💻 Response Console</h2>
        <div class="console" id="console">
            <!-- Console output will appear here -->
        </div>
        <button class="btn btn-clear" id="clearConsoleBtn" style="margin-top: 15px;">
            <span>🗑️</span>Clear Console
        </button>
    </div>

    <div class="section">
        <h2>📊 HTTP Transaction Details</h2>
        <div id="transactionDetails" class="transaction-details">
            <!-- Transaction details will appear here -->
        </div>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>

<script>
    (function() {
        'use strict';

        // ============================================================================
        // Configuration Module
        // ============================================================================
        const Config = {
            DIGEST_ALGORITHMS: {
                'MD5': CryptoJS.MD5,
                'MD5-sess': CryptoJS.MD5,
                'SHA-256': CryptoJS.SHA256,
                'SHA-256-sess': CryptoJS.SHA256,
                'SHA-512': CryptoJS.SHA512,
                'SHA-512-sess': CryptoJS.SHA512
            },
            USERS: [
                { username: 'john', password: 'password123', name: 'John', role: 'Regular User', email: 'john@example.com' },
                { username: 'jane', password: 'secret456', name: 'Jane', role: 'Regular User', email: 'jane@example.com' },
                { username: 'admin', password: 'admin123', name: 'Admin', role: 'Administrator', email: 'admin@company.com' }
            ],
            CONSOLE_TYPES: {
                SUCCESS: 'success',
                ERROR: 'error',
                INFO: 'info',
                WARNING: 'warning'
            }
        };

        // ============================================================================
        // Utility Functions Module
        // ============================================================================
        const Utils = {
            isValidEmail(email) {
                return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
            },

            isSessionAlgorithm(algorithm) {
                return algorithm && algorithm.endsWith('-sess');
            },

            formatTimestamp() {
                return new Date().toLocaleTimeString();
            },

            selectQop(qopString) {
                if (!qopString) return 'auth';
                const options = qopString.split(',').map(q => q.trim());
                return options.includes('auth') ? 'auth' :
                       options.includes('auth-int') ? 'auth-int' :
                       options[0] || 'auth';
            },

            parseAuthHeader(headerValue) {
                const params = {};
                const regex = /(\w+)=("([^"]+)"|([^,\s]+))/g;
                let match;
                while ((match = regex.exec(headerValue)) !== null) {
                    params[match[1]] = match[3] || match[4];
                }
                return params;
            }
        };

        // ============================================================================
        // DOM Utilities Module
        // ============================================================================
        const DOM = {
            get(id) {
                return document.getElementById(id);
            },

            create(tagName, className, textContent) {
                const element = document.createElement(tagName);
                if (className) element.className = className;
                if (textContent) element.textContent = textContent;
                return element;
            },

            clear(element) {
                if (typeof element === 'string') {
                    element = this.get(element);
                }
                if (element) {
                    element.innerHTML = '';
                }
            },

            show(element) {
                if (typeof element === 'string') {
                    element = this.get(element);
                }
                if (element) {
                    element.style.display = 'block';
                    element.classList.add('visible');
                }
            },

            hide(element) {
                if (typeof element === 'string') {
                    element = this.get(element);
                }
                if (element) {
                    element.style.display = 'none';
                    element.classList.remove('visible');
                }
            }
        };

        // ============================================================================
        // Logger Module
        // ============================================================================
        const Logger = {
            _log(message, type = Config.CONSOLE_TYPES.INFO) {
                const console = DOM.get('console');
                if (!console) return;

                const timestamp = Utils.formatTimestamp();
                const logEntry = DOM.create('div', `log-${type}`, `[${timestamp}] ${message}`);
                console.appendChild(logEntry);
                console.scrollTop = console.scrollHeight;
            },

            success(message) {
                this._log(message, Config.CONSOLE_TYPES.SUCCESS);
            },

            error(message) {
                this._log(message, Config.CONSOLE_TYPES.ERROR);
            },

            info(message) {
                this._log(message, Config.CONSOLE_TYPES.INFO);
            },

            warning(message) {
                this._log(message, Config.CONSOLE_TYPES.WARNING);
            },

            clear() {
                const console = DOM.get('console');
                if (console) {
                    console.innerHTML =
                        '<div class="log-success">Digest Authentication Client ready!</div>' +
                        '<div>Click on any endpoint button to test authentication.</div>';
                }
            }
        };

        // ============================================================================
        // Authentication State Module
        // ============================================================================
        const AuthState = {
            _state: {
                nonce: null,
                realm: null,
                algorithm: null,
                qop: null,
                opaque: null,
                nc: 0,
                username: null,
                password: null,
                isValid: false
            },

            get() {
                return { ...this._state };
            },

            update(realm, nonce, algorithm = 'MD5', qop = 'auth', opaque = '', nc = 0) {
                const credentials = CredentialManager.getCurrent();
                this._state = {
                    ...this._state,
                    realm,
                    nonce,
                    algorithm,
                    qop,
                    opaque,
                    nc,
                    username: credentials.username,
                    password: credentials.password,
                    isValid: true
                };

                UI.updateAuthStateDisplay();
                Logger.info(`Auth state updated - NC: ${this._state.nc.toString().padStart(8, '0')}`);
            },

            incrementNc() {
                this._state.nc++;
                UI.updateAuthStateDisplay();
                return this._state.nc.toString().padStart(8, '0');
            },

            reset() {
                this._state = {
                    nonce: null,
                    realm: null,
                    algorithm: null,
                    qop: null,
                    opaque: null,
                    nc: 0,
                    username: null,
                    password: null,
                    isValid: false
                };
                UI.updateAuthStateDisplay();
                Logger.warning('Authentication state reset');
            },

            isValid() {
                const credentials = CredentialManager.getCurrent();
                return this._state.isValid &&
                       this._state.nonce &&
                       this._state.username === credentials.username &&
                       this._state.password === credentials.password;
            }
        };

        // ============================================================================
        // Credential Manager Module
        // ============================================================================
        const CredentialManager = {
            getCurrent() {
                return {
                    username: DOM.get('username').value,
                    password: DOM.get('password').value
                };
            },

            set(username, password) {
                DOM.get('username').value = username;
                DOM.get('password').value = password;
            },

            validate() {
                const { username, password } = this.getCurrent();
                return username && password;
            }
        };

        // ============================================================================
        // Digest Authentication Module
        // ============================================================================
        const DigestAuth = {
            generateNonce() {
                const randomWords = CryptoJS.lib.WordArray.random(16);
                return randomWords.toString(CryptoJS.enc.Base64)
                    .replace(/[+/=]/g, '')
                    .substring(0, 22);
            },

            getBaseAlgorithm(algorithm) {
                return Utils.isSessionAlgorithm(algorithm) ? algorithm.replace('-sess', '') : algorithm;
            },

            computeHash(str, algorithm) {
                const hashFunc = Config.DIGEST_ALGORITHMS[algorithm];
                if (!hashFunc) {
                    Logger.error(`Unsupported algorithm: ${algorithm}, using MD5`);
                    return CryptoJS.MD5(str).toString();
                }
                return hashFunc(str).toString();
            },

            calculate(method, uri, username, password, realm, nonce, nc, cnonce, algorithm = 'MD5', qop = 'auth', requestBody = '') {
                const baseAlg = this.getBaseAlgorithm(algorithm);

                const initialHash = this.computeHash(`${username}:${realm}:${password}`, baseAlg);
                const ha1 = Utils.isSessionAlgorithm(algorithm)
                    ? this.computeHash(`${initialHash}:${nonce}:${cnonce}`, baseAlg)
                    : initialHash;

                const ha2 = qop === 'auth-int'
                    ? this.computeHash(`${method}:${uri}:${this.computeHash(requestBody, baseAlg)}`, baseAlg)
                    : this.computeHash(`${method}:${uri}`, baseAlg);

                const responseInput = `${ha1}:${nonce}:${nc}:${cnonce}:${qop}:${ha2}`;
                const response = this.computeHash(responseInput, baseAlg);

                return response;
            },

            createAuthHeader(username, realm, nonce, uri, algorithm = 'MD5', qop = 'auth', nc, cnonce, response, opaque = '') {
                return `Digest username="${username}", realm="${realm}", nonce="${nonce}", uri="${uri}", ` +
                       `algorithm="${algorithm}", qop="${qop}", nc="${nc}", cnonce="${cnonce}", ` +
                       `response="${response}", userhash=false, opaque="${opaque}"`;
            }
        };

        // ============================================================================
        // HTTP Transaction Module
        // ============================================================================
        const HTTPTransaction = {
            formatHeaders(headers) {
                let formatted = '';
                if (headers && typeof headers.forEach === 'function') {
                    headers.forEach((value, name) => {
                        formatted += `<span class="http-header-name">${name}:</span> <span class="http-header-value">${value}</span>\n`;
                    });
                } else if (headers && typeof headers === 'object') {
                    Object.entries(headers).forEach(([name, value]) => {
                        formatted += `<span class="http-header-name">${name}:</span> <span class="http-header-value">${value}</span>\n`;
                    });
                }
                return formatted;
            },

            formatRequest(method, endpoint, headers, body) {
                // For relative URLs, just use the endpoint path directly
                let request = `<span class="http-method">${method}</span> ${endpoint} HTTP/1.1\n`;
                request += `<span class="http-header-name">Host:</span> <span class="http-header-value">${window.location.host}</span>\n`;
                request += this.formatHeaders(headers);
                if (body) {
                    request += `\n${body}`;
                }
                return request;
            },

            formatResponse(response, body) {
                const statusClass = response.status === 200 ? 'http-status-200' :
                                   response.status === 401 ? 'http-status-401' : 'http-status-error';

                let formatted = `HTTP/1.1 <span class="${statusClass}">${response.status} ${response.statusText}</span>\n`;
                formatted += this.formatHeaders(response.headers);
                if (body) {
                    formatted += `\n${body}`;
                }
                return formatted;
            },

            display(transactions) {
                const detailsContainer = DOM.get('transactionDetails');
                if (!detailsContainer) return;

                let html = '';

                transactions.forEach((transaction, index) => {
                    if (index > 0) {
                        html += '<div class="transaction-flow">⬇️</div>';
                    }

                    html += `
                        <div class="http-message http-request">
                            <div class="http-message-header">🌐 ${transaction.type}</div>
                            <div class="http-message-content"><pre>${transaction.request}</pre></div>
                        </div>
                    `;

                    let responseClass = 'http-response-error';
                    if (transaction.response.status === 401) responseClass = 'http-response-401';
                    else if (transaction.response.status === 200) responseClass = 'http-response-success';

                    html += `
                        <div class="http-message ${responseClass}">
                            <div class="http-message-header">📨 ${transaction.responseType}</div>
                            <div class="http-message-content"><pre>${transaction.responseText}</pre></div>
                        </div>
                    `;
                });

                detailsContainer.innerHTML = html;
                DOM.show(detailsContainer);
            }
        };

        // ============================================================================
        // HTTP Client Module
        // ============================================================================
        const HTTPClient = {
            async makeRequest(endpoint, method = 'GET', body = null) {
                if (!CredentialManager.validate()) {
                    Logger.error('Please enter username and password');
                    return false;
                }

                const { username, password } = CredentialManager.getCurrent();

                Logger.info(`${method} ${endpoint}`);
                if (body) Logger.info(`Request Body: ${body}`);

                const transactions = [];

                try {
                    if (AuthState.isValid()) {
                        Logger.info('Reusing existing authentication state');
                        const success = await this._tryAuthenticatedRequest(endpoint, method, body, transactions);
                        if (success) {
                            HTTPTransaction.display(transactions);
                            return true;
                        }
                        Logger.warning('Existing auth state expired, getting new challenge');
                    }

                    return await this._performAuthFlow(endpoint, method, body, username, password, transactions);
                } catch (error) {
                    Logger.error(`Error: ${error.message}`);
                    if (transactions.length > 0) {
                        HTTPTransaction.display(transactions);
                    }
                    return false;
                } finally {
                    Logger.info('---');
                }
            },

            async _tryAuthenticatedRequest(endpoint, method, body, transactions) {
                const state = AuthState.get();
                const nc = AuthState.incrementNc();
                const cnonce = DigestAuth.generateNonce();
                const response = DigestAuth.calculate(
                    method,
                    endpoint,
                    state.username,
                    state.password,
                    state.realm,
                    state.nonce,
                    nc,
                    cnonce,
                    state.algorithm,
                    state.qop,
                    body
                );

                const authHeader = DigestAuth.createAuthHeader(
                    state.username,
                    state.realm,
                    state.nonce,
                    endpoint,
                    state.algorithm,
                    state.qop,
                    nc,
                    cnonce,
                    response,
                    state.opaque
                );
                Logger.info(`Reusing nonce with NC: ${nc}`);

                const authOptions = {
                    method,
                    headers: { 'Authorization': authHeader },
                    credentials: 'omit'
                };

                if (body && method !== 'GET') {
                    authOptions.headers['Content-Type'] = 'application/json';
                    authOptions.body = body;
                }

                const authResponse = await fetch(endpoint, authOptions);
                const authResponseBody = await authResponse.text();

                transactions.push({
                    type: 'Authenticated Request (Reused Nonce)',
                    request: HTTPTransaction.formatRequest(method, endpoint, authOptions.headers, body),
                    response: authResponse,
                    responseType: authResponse.status === 200 ? 'Success Response' : 'Auth Failed Response',
                    responseText: HTTPTransaction.formatResponse(authResponse, authResponseBody)
                });

                const success = authResponse.status === 200;
                Logger[success ? 'success' : 'warning'](`Auth Response: ${authResponse.status} ${authResponse.statusText}`);
                if (authResponseBody) Logger[success ? 'success' : 'warning'](`Response Body: ${authResponseBody}`);

                if (!success && authResponse.status === 401) {
                    const wwwAuth = authResponse.headers.get('WWW-Authenticate');
                    if (wwwAuth && wwwAuth.startsWith('Digest')) {
                        const newAuthParams = Utils.parseAuthHeader(wwwAuth);
                        if (newAuthParams.nonce && newAuthParams.nonce !== state.nonce) {
                            Logger.info('Received new challenge, updating auth state');
                            AuthState.update(
                                newAuthParams.realm,
                                newAuthParams.nonce,
                                newAuthParams.algorithm,
                                Utils.selectQop(newAuthParams.qop),
                                newAuthParams.opaque,
                                0
                            );
                            return await this._tryAuthenticatedRequest(endpoint, method, body, transactions);
                        }
                    }
                    AuthState.reset();
                }

                return success;
            },

            async _performAuthFlow(endpoint, method, body, username, password, transactions) {
                const options = { method, credentials: 'omit' };
                const requestHeaders = {};

                if (body && method !== 'GET') {
                    requestHeaders['Content-Type'] = 'application/json';
                    options.headers = requestHeaders;
                    options.body = body;
                }

                const response = await fetch(endpoint, options);
                const responseBody = await response.text();

                transactions.push({
                    type: 'Initial Request',
                    request: HTTPTransaction.formatRequest(method, endpoint, requestHeaders, body),
                    response: response,
                    responseType: 'Challenge Response (401)',
                    responseText: HTTPTransaction.formatResponse(response, responseBody)
                });

                Logger[response.status === 200 ? 'success' : 'info'](`Status: ${response.status} ${response.statusText}`);

                if (response.status === 401) {
                    const authSuccess = await this._handleAuthChallenge(response, endpoint, method, body, username, password, transactions);
                    HTTPTransaction.display(transactions);
                    return authSuccess;
                } else {
                    Logger.success(`Response: ${responseBody}`);
                    HTTPTransaction.display(transactions);
                    return true;
                }
            },

            async _handleAuthChallenge(response, endpoint, method, body, username, password, transactions) {
                const wwwAuth = response.headers.get('WWW-Authenticate');
                if (!wwwAuth || !wwwAuth.startsWith('Digest')) {
                    Logger.error('No valid WWW-Authenticate header');
                    return false;
                }

                const authParams = Utils.parseAuthHeader(wwwAuth);
                const selectedQop = Utils.selectQop(authParams.qop);
                authParams.qop = selectedQop;

                AuthState.update(
                    authParams.realm,
                    authParams.nonce,
                    authParams.algorithm,
                    selectedQop,
                    authParams.opaque,
                    0
                );

                Logger.info(`Auth params: realm="${authParams.realm}", qop="${selectedQop}", algorithm="${authParams.algorithm || 'MD5'}"`);

                const nc = AuthState.incrementNc();
                const cnonce = DigestAuth.generateNonce();
                const digestResponse = DigestAuth.calculate(
                    method,
                    endpoint,
                    username,
                    password,
                    authParams.realm,
                    authParams.nonce,
                    nc,
                    cnonce,
                    authParams.algorithm,
                    selectedQop,
                    body
                );
                const authHeader = DigestAuth.createAuthHeader(
                    username,
                    authParams.realm,
                    authParams.nonce,
                    endpoint,
                    authParams.algorithm,
                    selectedQop,
                    nc,
                    cnonce,
                    digestResponse,
                    authParams.opaque
                );

                Logger.info(`Authorization: ${authHeader}`);

                const authOptions = {
                    method,
                    headers: { 'Authorization': authHeader },
                    credentials: 'omit'
                };

                if (body && method !== 'GET') {
                    authOptions.headers['Content-Type'] = 'application/json';
                    authOptions.body = body;
                }

                const authResponse = await fetch(endpoint, authOptions);
                const authResponseBody = await authResponse.text();

                transactions.push({
                    type: 'Authenticated Request (New Challenge)',
                    request: HTTPTransaction.formatRequest(method, endpoint, authOptions.headers, body),
                    response: authResponse,
                    responseType: authResponse.status === 200 ? 'Success Response' : 'Auth Failed Response',
                    responseText: HTTPTransaction.formatResponse(authResponse, authResponseBody)
                });

                const success = authResponse.status === 200;
                Logger[success ? 'success' : 'error'](`Auth Response: ${authResponse.status} ${authResponse.statusText}`);
                if (authResponseBody) Logger[success ? 'success' : 'error'](`Response Body: ${authResponseBody}`);

                if (!success) {
                    AuthState.reset();
                }

                return success;
            }
        };

        // ============================================================================
        // UI Module
        // ============================================================================
        const UI = {
            init() {
                this._renderUserCards();
                this._setInitialUser();
                this.updateAuthStateDisplay();
                this._initializeConsole();
                this._clearTransactionDetails();
            },

            _renderUserCards() {
                const userGrid = DOM.get('userGrid');
                if (!userGrid) return;

                userGrid.innerHTML = Config.USERS.map((user, index) => `
                    <div class="user-card ${index === 0 ? 'active' : ''}"
                         data-username="${user.username}"
                         data-password="${user.password}">
                        <h4>${user.name}</h4>
                        <p>${user.role}</p>
                        <p class="user-email">${user.email}</p>
                    </div>
                `).join('');
            },

            _setInitialUser() {
                const firstUser = Config.USERS[0];
                if (firstUser) {
                    CredentialManager.set(firstUser.username, firstUser.password);
                }
            },

            updateAuthStateDisplay() {
                const container = DOM.get('authStateContent');
                if (!container) return;

                const state = AuthState.get();

                if (!state.isValid || !state.nonce) {
                    container.innerHTML = `
                        <p style="text-align: center; color: #6c757d; font-style: italic;">
                            No active authentication session
                        </p>
                    `;
                    return;
                }

                const ncFormatted = state.nc.toString().padStart(8, '0');

                container.innerHTML = `
                    <div class="auth-info">
                        <div class="auth-param">
                            <div class="auth-param-name">Username</div>
                            <div class="auth-param-value">${state.username || 'N/A'}</div>
                        </div>
                        <div class="auth-param">
                            <div class="auth-param-name">Realm</div>
                            <div class="auth-param-value">${state.realm || 'N/A'}</div>
                        </div>
                        <div class="auth-param">
                            <div class="auth-param-name">Nonce</div>
                            <div class="auth-param-value">${state.nonce ? state.nonce.substring(0, 20) + '...' : 'N/A'}</div>
                        </div>
                        <div class="auth-param">
                            <div class="auth-param-name">Algorithm</div>
                            <div class="auth-param-value">${state.algorithm || 'MD5'}</div>
                        </div>
                        <div class="auth-param">
                            <div class="auth-param-name">QOP</div>
                            <div class="auth-param-value">${state.qop || 'auth'}</div>
                        </div>
                        <div class="auth-param">
                            <div class="auth-param-name">NC (Request Count)</div>
                            <div class="auth-param-value">${ncFormatted}</div>
                        </div>
                    </div>
                `;
            },

            _initializeConsole() {
                Logger.clear();
                Logger.info('Digest Authentication Client initialized');
                Logger.info('Users: john/password123, jane/secret456, admin/admin123');
            },

            _clearTransactionDetails() {
                const detailsContainer = DOM.get('transactionDetails');
                if (detailsContainer) {
                    detailsContainer.innerHTML = `
                        <p style="text-align: center; color: #6c757d; font-style: italic;">
                            Click any endpoint button to see detailed HTTP request/response messages
                        </p>
                    `;
                    DOM.hide(detailsContainer);
                }
            },

            setActiveUser(username, password) {
                document.querySelectorAll('.user-card').forEach(card => {
                    card.classList.toggle('active', card.dataset.username === username);
                });

                CredentialManager.set(username, password);
                AuthState.reset();
                Logger.info(`Selected user: ${username}`);
            }
        };

        // ============================================================================
        // Event Handler Module
        // ============================================================================
        const EventHandlers = {
            init() {
                this._setupUserCardHandlers();
                this._setupCredentialChangeHandlers();
                this._setupButtonHandlers();
            },

            _setupUserCardHandlers() {
                document.addEventListener('click', (e) => {
                    const userCard = e.target.closest('.user-card');
                    if (userCard) {
                        UI.setActiveUser(userCard.dataset.username, userCard.dataset.password);
                    }
                });
            },

            _setupCredentialChangeHandlers() {
                ['username', 'password'].forEach(id => {
                    const input = DOM.get(id);
                    if (input) {
                        input.addEventListener('input', () => {
                            const currentCreds = CredentialManager.getCurrent();
                            const state = AuthState.get();

                            if (state.isValid &&
                                (state.username !== currentCreds.username ||
                                 state.password !== currentCreds.password)) {
                                AuthState.reset();
                                Logger.warning('Credentials changed, auth state reset');
                            }
                        });
                    }
                });
            },

            _setupButtonHandlers() {
                // Reset auth button
                const resetBtn = DOM.get('resetAuthBtn');
                if (resetBtn) {
                    resetBtn.addEventListener('click', () => AuthState.reset());
                }

                // Clear console button
                const clearBtn = DOM.get('clearConsoleBtn');
                if (clearBtn) {
                    clearBtn.addEventListener('click', () => {
                        Logger.clear();
                        UI._clearTransactionDetails();
                    });
                }

                // Update email button
                const updateEmailBtn = DOM.get('updateEmailBtn');
                if (updateEmailBtn) {
                    updateEmailBtn.addEventListener('click', () => this._handleEmailUpdate());
                }

                // Endpoint buttons
                document.addEventListener('click', (e) => {
                    if (e.target.closest('[data-endpoint]')) {
                        const endpoint = e.target.closest('[data-endpoint]').dataset.endpoint;
                        HTTPClient.makeRequest(endpoint);
                    }
                });
            },

            async _handleEmailUpdate() {
                const newEmailInput = DOM.get('newEmail');
                if (!newEmailInput) return;

                const newEmail = newEmailInput.value.trim();

                if (!newEmail) {
                    Logger.error('Please enter a new email address');
                    return;
                }

                if (!Utils.isValidEmail(newEmail)) {
                    Logger.error('Please enter a valid email address');
                    return;
                }

                const body = JSON.stringify({ email: newEmail });
                const success = await HTTPClient.makeRequest('/profile/email', 'PUT', body);

                if (success) {
                    newEmailInput.value = '';
                    Logger.info('Email field cleared after successful update');
                }
            }
        };

        // ============================================================================
        // Application Controller
        // ============================================================================
        const App = {
            init() {
                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', () => this._initialize());
                } else {
                    this._initialize();
                }
            },

            _initialize() {
                UI.init();
                EventHandlers.init();
                Logger.success('Digest Authentication Client ready!');
            }
        };

        // ============================================================================
        // Initialize Application
        // ============================================================================
        App.init();

    })();
</script>
</body>
</html>
